/******************************************************************************
秋夜静，独坐对残灯。
啼笑非非谁识我，坐行梦梦尽缘君，何所慰消沉。
风卷雨，雨复卷侬心。
心似欲随风雨去，茫茫大海任浮沉。
无爱亦无恨。
******************************************************************************/
#include "kbRGB_Int.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "kbRGB_Int_Effect.h"

enum
{
    ZONE_TYPE_SINGLE,
    ZONE_TYPE_LINEAR,
    ZONE_TYPE_MATRIX
};

static hsv_t RandomHSVColor()
{
    hsv_t hsv;

    hsv.hue = kb_rand() % 360;
    hsv.saturation = 255;
    hsv.value = 255;

    return hsv;
}
static uint32_t RandomRGBColor()
{
    hsv_t hsv = RandomHSVColor();
    return (hsv2rgb(&hsv));
}
static uint32_t Enlight(uint32_t color, float value)
{
    hsv_t hsv;
    rgb2hsv(color, &hsv);

    hsv.value *= value;

    return (hsv2rgb(&hsv));
}
static unsigned char InterpolateChanel(unsigned char a, unsigned char b, float x)
{
    return (int) ((b - a) * x + a);
}
#define RGBGetRValue(rgb)   (rgb & 0x000000FF)
#define RGBGetGValue(rgb)   ((rgb >> 8) & 0x000000FF)
#define RGBGetBValue(rgb)   ((rgb >> 16) & 0x000000FF)
#define ToRGBColor(r, g, b) ((uint32_t)((b << 16) | (g << 8) | (r)))
static uint32_t Interpolate(uint32_t color1, uint32_t color2, float fraction)
{
    return ToRGBColor(
                InterpolateChanel(RGBGetRValue(color1), RGBGetRValue(color2), fraction),
                InterpolateChanel(RGBGetGValue(color1), RGBGetGValue(color2), fraction),
                InterpolateChanel(RGBGetBValue(color1), RGBGetBValue(color2), fraction)
                );
}
static uint32_t Invert(uint32_t color)
{
    int r = (255-RGBGetRValue(color));
    int g = (255-RGBGetGValue(color));
    int b = (255-RGBGetBValue(color));

    return ToRGBColor(r, g, b);
}
static unsigned char ScreenChanel(unsigned char a, unsigned char b)
{
    return 255 - ((255 - b) * (255 - a) >> 8);;
}
static uint32_t Screen(uint32_t color1, uint32_t color2)
{
    return ToRGBColor(
                ScreenChanel(RGBGetRValue(color1), RGBGetRValue(color2)),
                ScreenChanel(RGBGetGValue(color1), RGBGetGValue(color2)),
                ScreenChanel(RGBGetBValue(color1), RGBGetBValue(color2))
                );
};

/*************************************************************************************************\
|        BouncingBallEffect [9]                                                                              |
\*************************************************************************************************/
void kbRGB_Int_BouncingBallEffect_Init(struct kbRGB_Int_Params *const params)    // 弹力球
{
    struct kbRGB_Int_BouncingBall_t *const Ball = &params->Advanced_BouncingBall;
    params->time = 1000.0;
    params->FPS = 16;
    params->Speed = 100;
    params->Slider2Val = 30;
    params->progress = 0.f;
    params->background = 0x00;
    Ball->radius = 2;//ui->ball_radius_slider->value();
    Ball->gravity = 10;//ui->gravity_slider->value();
    Ball->horizontalVelocity = 70+(kb_rand()&0x7F);//ui->horizontal_velocity_slider->value();
    Ball->spectrumVelocity = 50+(kb_rand()&0x7F);//ui->spectrum_velocity_slider->value();
    Ball->dropHeightPercent = 90;//ui->drop_height_percent_slider->value();
    Ball->Ball.x = 0;
    Ball->Ball.y = 0;
}
static uint32_t BouncingBall_GetColor(const unsigned int x, const unsigned int y, const int16_t cx, const int16_t cy, const int16_t w, const int16_t h, const int32_t _progress, const int reverse)
{
    //float direction_mult = -1.0f;//direction == 0 ? 1.f : -1.f;
    //double angle;
    int16_t side = h;//(h+w)/2;
    //struct kbRGB_Pixel piont;
    int16_t hue;// = (float)(kbrgb_Params.progress + (int)(180 + direction_mult * (reverse ? atan2(y - cy, x - cx) : atan2(x - cx, y - cy)) * (180.0 / 3.14159)) % 360);
    //piont.pixel = kbRGB_Angle_IntGet((x - cx/(float)kbRGB_SinMax), (y - cy/(float)kbRGB_SinMax));
    //angle = piont.angle/(float)(0x1<<KBRGB_ANGLE_INT_PRE);
    //if(piont.radius >= radius) return 0x00;
    if(side>w) side=w;
    //float distance = sqrt(pow(0.00 + (x-cx/(float)kbRGB_SinMax)/side, 2) + pow(0.00 + (y-cy/(float)kbRGB_SinMax)/side, 2));
    //float distance = sqrt(pow(0.00 + (x*kbRGB_SinMax-(float)cx)/kbRGB_SinMax / side, 2) + pow(0.00 + (y*kbRGB_SinMax-(float)cy)/kbRGB_SinMax/side, 2));
    float distance = kb_sqrt(pow(0.00 + (x*kbRGB_SinMax-(float)cx), 2) + pow(0.00 + (y*kbRGB_SinMax-(float)cy), 2)) / (float)(kbRGB_SinMax*side);
    //float distance = piont.radius/(float)(0x1<<KBRGB_RADIUS_INT_PRE)/side;
//    if(piont.radius <1) return 0x00;
    //if(distance >= radius) return 0x00;
    //hue = (float)(kbrgb_Params.progress + (int)(180 + direction_mult * (reverse ? atan2(y - cy, x - cx) : atan2(x - cx, y - cy)) * (180.0 / 3.14159)) % 360);
    //hue = (float)((int)(kbrgb_Params.progress + 360 + /*direction_mult **/(reverse ? angle : 90.0f-angle)) % 360);
    //hue = (float)((int)(kbrgb_Params.progress + 360 + 360*distance + /*direction_mult **/(reverse ? angle : 90.0f-angle)) % 360);
    //hue = ((int)(_progress*0 + 360 + 360*distance ) % 360);
	hue = ((int)((_progress>>2) + 360) % 360);
    //hue = (float)((int)(kbrgb_Params.progress) % 360);
    //hue = (float)(kbrgb_Params.progress + (int)(180 + (atan2(x - cx, y - cy)) * (180.0 / 3.14159)) % 360);
    //hue = (float)(kbrgb_Params.progress + (int)(360 - angle) % 360);
    hsv_t hsv = { 0, 0, 0 };
    hsv.hue = (int)hue;
    hsv.saturation = 255;
    hsv.value = 255;
    //if(piont.radius>0) hsv.value = (255+128)/piont.radius;
    //hsv.value = (255+255)/(piont.radius+2);
    if(distance>=0.7) hsv.value=0;
    else if(distance<=0.05) hsv.value=255;
    else hsv.value = 255*(1-distance)*(1-distance)*(1-distance)*(1-distance);//hsv.saturation = 255*(1-distance);//hsv.saturation = 255*pow((1-distance), 2);
    //hsv.value = hsv.saturation;

    return (hsv2rgb(&hsv));
}
void kbRGB_Int_BouncingBallEffect(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 弹力球
{
    struct kbRGB_Int_BouncingBall_t *const Ball = &params->Advanced_BouncingBall;
    //double k = kbrgb_Params.progress-((int)kbrgb_Params.progress);
    int16_t k = params->progress&kbRGB_PRE_MAX;
    int32_t cx = kbRGB_Sin_Int(Ball->Ball.x*2/kbRGB_PRE_MAX)*cols;///(float)kbRGB_SinMax;//*10.0f;
    int32_t cy = kbRGB_Sin_Int(Ball->Ball.y*2/kbRGB_PRE_MAX)*rows;///(float)kbRGB_SinMax;//*10.0f;

    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
         for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = BouncingBall_GetColor(col_id, row_id, cx, cy, cols, rows, params->progress>>kbRGB_PRE_BIT, 0);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    params->progress += ((params->Speed+speed*20)<<kbRGB_PRE_BIT)/ params->FPS;
    Ball->Ball.x +=  (Ball->spectrumVelocity<<kbRGB_PRE_BIT)*180/(KBRGB_PI*params->FPS*100);
    Ball->Ball.y +=  (Ball->horizontalVelocity<<kbRGB_PRE_BIT)*180/(KBRGB_PI*params->FPS*100);
    if(Ball->Ball.x>=(180<<kbRGB_PRE_BIT)) Ball->Ball.x -= (180<<kbRGB_PRE_BIT);
    if(Ball->Ball.y>=(180<<kbRGB_PRE_BIT)) Ball->Ball.y -= (180<<kbRGB_PRE_BIT);
    if((cx>=(cols*kbRGB_SinMax-10)) || (cx<=(10))) Ball->horizontalVelocity = 20+(kb_rand()&0x7F)+(k*30>>kbRGB_PRE_BIT);//ui->horizontal_velocity_slider->value();
    if((cy>=(rows*kbRGB_SinMax-10)) || (cy<=(10))) Ball->spectrumVelocity = 30+(kb_rand()&0x7F)+(k*30>>kbRGB_PRE_BIT);//ui->spectrum_velocity_slider->value();
    //printf("[%s--%d] cx:%8f cy:%8f \r\n", __func__, __LINE__, cx, cy);
    //fflush(stdout);
}

/*************************************************************************************************\
|        Bubbles [9]                                                                              |
\*************************************************************************************************/
void kbRGB_Int_Bubbles_Init(struct kbRGB_Int_Params *const params)    // 气泡
{
    struct kbRGB_Int_Bubbles_t *const Bubbles = &params->Advanced_Bubbles;
    params->time = 1000.0;
    params->FPS = 60;
    params->Speed = 80;
    params->Slider2Val = 30;
    params->progress = 0.f;
    params->background = 0x00;
    Bubbles->max_bubbles = KB_RGB_BUBBLES;
    Bubbles->rarity = 8;
    Bubbles->speed_mult = 10;
    Bubbles->max_expansion = 100;
    Bubbles->thickness = 2;
}
static uint32_t Bubbles_GetColor(int x, int y, int w, int h, struct kbRGB_Int_Bubbles_t *const Bubbles,const uint32_t background)
{
    int color_idx = -1;
    int val = 0;

    for(unsigned int i = 0; i < Bubbles->bubblesSize; i++)
    {
//        double distance = sqrt(pow(w * Bubbles->centers[i].x - (x<<kbRGB_PRE_BIT), 2) + pow(h * Bubbles->centers[i].y - (y<<kbRGB_PRE_BIT), 2)) / (float)(0x1<<kbRGB_PRE_BIT);
//        double shallow = fabs(distance*(0x1<<kbRGB_PRE_BIT) - Bubbles->bubbles[i]) / ( 0.1 * Bubbles->thickness*(0x1<<kbRGB_PRE_BIT));
        double distance = kb_sqrt(pow(w * Bubbles->centers[i].x - (x<<kbRGB_PRE_BIT), 2) + pow(h * Bubbles->centers[i].y - (y<<kbRGB_PRE_BIT), 2));
        double shallow = fabs(distance - Bubbles->bubbles[i]) / ( 0.1 * Bubbles->thickness*(0x1<<kbRGB_PRE_BIT));
        //double value = std::min<double>(255, 255 * (1 / pow(shallow, 2)));
        //double value = 255 * (1 / pow(shallow, 2));
        double value = 255 * (1 / shallow);
        if(value>255) value = 255;

        if(value > val)
        {
            color_idx = i;
            val = value;
        }
    }

    if(color_idx >= 0)
    {
        hsv_t final;

        rgb2hsv(Bubbles->colors[color_idx], &final);

        final.value = val;
        return /*ColorUtils::*/Screen(hsv2rgb(&final), background);
    }
    else
    {
        return background;
    }

}
static void Bubbles_InitBubble(struct kbRGB_Int_Bubbles_t *const Bubbles)
{
    uint16_t  bubblesSize = Bubbles->bubblesSize;
    Bubbles->bubbles[bubblesSize]=0;

//    double speed = 1 + 10 * (((double)kb_rand() / RAND_MAX) - 1) *(-1);
//    Bubbles->speeds[bubblesSize]=(speed)*(0x1<<kbRGB_PRE_BIT);
    uint16_t speed = kbRGB_PRE_MAX + 10 * (kbRGB_PRE_MAX-(kb_rand()&kbRGB_PRE_MAX));// / kbRGB_PRE_MAX;
    Bubbles->speeds[bubblesSize]=(speed);//*(0x1<<kbRGB_PRE_BIT);

    uint32_t color;

    color = RandomRGBColor();

    Bubbles->colors[bubblesSize]=(color);

//    Bubbles->centers[bubblesSize].x = (((double)kb_rand() / RAND_MAX) - 1) *(-1)*(0x1<<kbRGB_PRE_BIT);
//    Bubbles->centers[bubblesSize].y = (((double)kb_rand() / RAND_MAX) - 1) *(-1)*(0x1<<kbRGB_PRE_BIT);
//    Bubbles->centers[bubblesSize].x = (1-((double)(kb_rand()&kbRGB_PRE_MAX) / kbRGB_PRE_MAX))*(0x1<<kbRGB_PRE_BIT);
//    Bubbles->centers[bubblesSize].y = (1-((double)(kb_rand()&kbRGB_PRE_MAX) / kbRGB_PRE_MAX))*(0x1<<kbRGB_PRE_BIT);
    Bubbles->centers[bubblesSize].x = (kbRGB_PRE_MAX-(kb_rand()&kbRGB_PRE_MAX) );
    Bubbles->centers[bubblesSize].y = (kbRGB_PRE_MAX-(kb_rand()&kbRGB_PRE_MAX) );
    //centers.push_back(QPointF(x, y));
    Bubbles->bubblesSize++;
}

static void Bubbles_Cleanup(struct kbRGB_Int_Bubbles_t *const Bubbles)
{
    for(unsigned int i = 0; i < Bubbles->bubblesSize; i++)
    {
        if(Bubbles->bubbles[i] > (Bubbles->max_expansion<<kbRGB_PRE_BIT))
        {
            for(uint32_t kk = i; kk < Bubbles->bubblesSize-1; kk++)
            {
                Bubbles->bubbles[kk] = Bubbles->bubbles[kk+1];
                Bubbles->centers[kk].x = Bubbles->centers[kk+1].x;
                Bubbles->centers[kk].y = Bubbles->centers[kk+1].y;
                Bubbles->speeds[kk] = Bubbles->speeds[kk+1];
                Bubbles->colors[kk] = Bubbles->colors[kk+1];
            }
            Bubbles->bubblesSize--;
            break;
        }
    }
}

void kbRGB_Int_Bubbles(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 气泡
{
    struct kbRGB_Int_Bubbles_t *const Bubbles = &params->Advanced_Bubbles;
    uint16_t  bubblesSize = Bubbles->bubblesSize;
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = Bubbles_GetColor(col_id, row_id, cols, rows, Bubbles, params->background);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    for(uint16_t i = 0; i < bubblesSize; i++)
    {
        //Bubbles->bubbles[i] += 0.2 * Bubbles->speed_mult * Bubbles->speeds[i] / (float) FPS;
        Bubbles->bubbles[i] += 2 * Bubbles->speed_mult * Bubbles->speeds[i] / (params->FPS*10);
    }

    if(((kb_rand() % Bubbles->rarity) == 0) && (bubblesSize < Bubbles->max_bubbles))
    {
        Bubbles_InitBubble(Bubbles);
    }

    Bubbles_Cleanup(Bubbles);
}

/*************************************************************************************************\
|        FractalMotion [9]                                                                              |
\*************************************************************************************************/
void kbRGB_Int_FractalMotion_Init(struct kbRGB_Int_Params *const params)    // 分形运动
{
    struct kbRGB_Int_FractalMotion_t *const Fractal = &params->Advanced_FractalMotion;
    params->time = 1000.0;
    params->FPS = 60;
    params->Speed = 70;
    params->Slider2Val = 30;
    params->progress = 0;
    params->background = 0x00;
    Fractal->random_color = RandomRGBColor();
    Fractal->next_random_color = RandomRGBColor();
    Fractal->val_mult = 100;
    Fractal->inv_val_mult = 0.01f;//1.f / val_mult;
    Fractal->random_tick = 0.f;
    Fractal->thickness = 1;
    Fractal->amplitude = 6.f;
    Fractal->frequency = 30.f;
    Fractal->freq_m1 = 2.1;
    Fractal->freq_m2 = 4.5;
    Fractal->freq_m3 = 1.72;
    Fractal->freq_m4 = 1.121;
    Fractal->freq_m5 = 4.0;
    Fractal->freq_m6 = 2.221;
    Fractal->freq_m7 = 0.437;
    Fractal->freq_m8 = 5.0;
    Fractal->freq_m9 = 2.1122;
    Fractal->freq_m10 = 1.5;
    Fractal->freq_m11 = 1.72;
    Fractal->freq_m12 = 0.06;
}
static uint32_t FractalMotion_GetColor(unsigned int x, unsigned int ly, unsigned int h, const int32_t _progress, const unsigned int _Speed, const uint32_t background, struct kbRGB_Int_FractalMotion_t *const Fractal)
{
    float f = Fractal->frequency * 0.01;
    float y = sin(x * f);
    float t = 0.01*(-_progress/(float)kbRGB_PRE_MAX*_Speed);
#if 1
    y += sin(x*f*Fractal->freq_m1 + t)*Fractal->freq_m2;
    //y += sin(x*f*freq_m3 + t*freq_m4)*freq_m5;
    //y += sin(x*f*freq_m6 + t*freq_m7)*freq_m8;
    //y += sin(x*f*freq_m9+ t*freq_m10)*freq_m11;
    y *= 0.1 * Fractal->amplitude*Fractal->freq_m12;
#else
    y += sin(x*f*freq_m1 + t)*freq_m2;
    y *= 0.1 * amplitude*freq_m12;
#endif

    y = (1 + y) * 0.5 * h;

    float distance = fabs(y - ly);

    if(distance > Fractal->thickness)
    {
        return background;
    }

    uint32_t color;

    //color = /*ColorUtils::*/Interpolate(random_color, next_random_color, std::min<float>(1.f, random_tick));
    if(1.f< Fractal->random_tick) color = /*ColorUtils::*/Interpolate(Fractal->random_color, Fractal->next_random_color, 1.0f);
    else color = /*ColorUtils::*/Interpolate(Fractal->random_color, Fractal->next_random_color, Fractal->random_tick);

    return /*ColorUtils::*/Interpolate(color, background, distance / Fractal->thickness);
}
void kbRGB_Int_FractalMotion(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 分形运动
{
    struct kbRGB_Int_FractalMotion_t *const Fractal = &params->Advanced_FractalMotion;
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = FractalMotion_GetColor(col_id, row_id, rows, params->progress, params->Speed, params->background, Fractal);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    float delta = (float) params->Speed / (float) params->FPS;

    if(Fractal->random_tick >= 1)
    {
        Fractal->random_color = Fractal->next_random_color;
        Fractal->next_random_color = /*ColorUtils::*/RandomRGBColor();
        Fractal->random_tick = 0;
    }

    Fractal->random_tick += 0.005 * delta;
    //progress += 0.1 * delta;
    params->progress += (params->Speed<<kbRGB_PRE_BIT) / (params->FPS*10);
}

/*************************************************************************************************\
|        Sinusoid [9]                                                                              |
\*************************************************************************************************/
void kbRGB_Int_Sinusoid_Init(struct kbRGB_Int_Params *const params)    // 正弦曲线
{
    params->time = 1000.0;
    params->FPS = 60;
    params->Speed = 100;
    params->Slider2Val = 45;//60;
    params->progress = 0;
}
//void kbRGB_Int_DoubleSinusoid_Init(struct kbRGB_Int_Params *const params)    // 双正弦曲线
//{
//    kbRGB_Int_Sinusoid_Init(params);
//    params->Slider2Val = params->Slider2Val | (0x1<<16);
//}
void kbRGB_Int_Sinusoid(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 正弦曲线
{
    int16_t _sin;
	int16_t col;
    float _sin2;
	uint16_t Slider2Val = params->Slider2Val&0xFFFF;
    hsv_t hsv;
    hsv.saturation = 255;
    hsv.value = 255;
    hsv.hue = 0;
    //params->progress = 0;
    const int16_t angle2 = (params->progress>>kbRGB_PRE_BIT);
    const int16_t angle = (params->progress>>(kbRGB_PRE_BIT-2));
    _sin2 = (kbRGB_SinMax+kbRGB_Sin_Int(angle2)) / (float)(2*kbRGB_SinMax);
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        col = col_id;
        if(reverse) col = -col;
        _sin = kbRGB_Sin_Int(angle+col*Slider2Val);
        float hight = (kbRGB_SinMax+_sin)/(float)(2*kbRGB_SinMax);
        //printf("[%s--%d] col_id:%2d hight:%8f ", __func__, __LINE__, col_id, hight);
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            //uint32_t color = Sinusoid_GetColor(col_id, row_id, rows, params->progress, params->Speed, params->background, Fractal);
            float diff = hight*4 - row_id;
            //printf("diff:%2d ", (int)diff);
            diff = diff/(rows+0);
            if(diff<0) diff=-diff;
            //printf("diff:%8f ", diff);
#if 1
            //hsv.hue = 360*diff*diff;
			hsv.hue = 360*diff+(angle2>>2);
			hsv.hue = hsv.hue%360;
#else
            hsv.hue = 360*_sin2;//*diff;
            //hsv.hue = params->progress>>kbRGB_PRE_BIT;
            hsv.hue = hsv.hue%360;
            diff = hight*rows - row_id;
            diff = diff/(rows*1);
            if(diff<0) diff=-diff;
            hsv.value = 255*(1-diff)*(1-diff)*(1-diff)*(1-diff);
#endif
            uint32_t color = hsv2rgb(&hsv);
            kbRGB_pset(col_id, row_id, color);
        }
        //printf("\r\n");
    }
    //fflush(stdout);
    params->progress += ((params->Speed+speed*30)<<kbRGB_PRE_BIT) / (params->FPS+10);
}
static void _kbRGB_Int_DoubleSinusoid(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, const int Double, struct kbRGB_Int_Params *const params)    // 双正弦曲线
{
    int16_t _sin;
    int16_t col;
    float _sin2;
	//const int Double = (params->Slider2Val>>16)&0x1;
	uint16_t Slider2Val = params->Slider2Val&0xFFFF;
    hsv_t hsv;
    hsv.saturation = 255;
    hsv.value = 255;
    hsv.hue = 0;
    //params->progress = 0;
    const int16_t angle2 = (params->progress>>kbRGB_PRE_BIT);
    const int16_t angle = (params->progress>>(kbRGB_PRE_BIT-3));
    _sin2 = (kbRGB_SinMax+kbRGB_Sin_Int(angle2)) / (float)(2*kbRGB_SinMax);
    //printf("[%s--%d] angle:%3d _sin2:%8f \r\n", __func__, __LINE__, angle, _sin2);
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        col = col_id - (cols>>1);
        //if(col<0) col = -col;
        // Double 值为 1 表示双正弦曲线
        if((Double) && (col<0)) col = -col;
        if(!reverse) col = -col;
        _sin = kbRGB_Sin_Int(angle+col*Slider2Val);
        float hight = (kbRGB_SinMax+_sin)/(float)(2*kbRGB_SinMax);
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            float diff = hight*4 - row_id;
            diff = diff/(float)(rows+0);
            if(diff<0) diff=-diff;
            //hsv.hue = 360*_sin2;//*diff;
			//hsv.hue =  360+360*_sin2 + col_id*10;
            if(Double)
            {
                if(col<0) col = -col;
                hsv.hue =  360+360*_sin2 + col*10;
            }
            else hsv.hue =  360+360*_sin2 + col_id*10;
            hsv.hue = hsv.hue%360;
            diff = hight*rows - row_id;
            diff = diff/(rows*1);
            if(diff<0) diff=-diff;
            hsv.value = 255*(1-diff)*(1-diff)*(1-diff)*(1-diff)*(1-diff)*(1-diff);//*(1-diff)*(1-diff);
            uint32_t color = hsv2rgb(&hsv);
            kbRGB_pset(col_id, row_id, color);
        }
        //printf("\r\n");
    }
    //fflush(stdout);
    params->progress += ((params->Speed+speed*30)<<kbRGB_PRE_BIT) / (params->FPS+10);
}
void kbRGB_Int_SingleSinusoid(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 单正弦曲线
{
    _kbRGB_Int_DoubleSinusoid(cols, rows, speed, reverse, 0, params);    // 双正弦曲线
}
void kbRGB_Int_DoubleSinusoid(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 双正弦曲线
{
    _kbRGB_Int_DoubleSinusoid(cols, rows, speed, reverse, 1, params);    // 双正弦曲线
}

/*************************************************************************************************\
|        GradientWave [9]                                                                              |
\*************************************************************************************************/
void kbRGB_Int_GradientWave_Init(struct kbRGB_Int_Params *const params)    // 梯度波
{
    params->Speed = 25;
    params->Slider2Val = 30;
    params->spread = 30;
}
static uint32_t CustomGradientWave_GetColor(const uint16_t x, const uint16_t w, const int32_t _progress, const int spread)
{
//    float i = (spread/100.f) * x / w + _progress/(float)(0x1<<kbRGB_PRE_BIT);
//    i -= (long) i;
    int32_t i = (spread * x * (0x1<<kbRGB_PRE_BIT)) / (w*100) + _progress;
    i &= kbRGB_PRE_MAX;
    hsv_t HSVVal;
    HSVVal.saturation = 255;
    HSVVal.value      = 255;
    //HSVVal.hue = ((int)(360.0 * i))%360;
    HSVVal.hue = ((int)(360.0 * i)>>kbRGB_PRE_BIT)%360;
    //return /*ColorUtils::*/fromQColor(gradient.pixelColor(100.0 * i, 0));
    return hsv2rgb(&HSVVal);
}
void kbRGB_Int_GradientWave(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 梯度波
{
    //int reverse=0;
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        uint32_t color = CustomGradientWave_GetColor(reverse ? cols - col_id - 1: col_id, cols, params->progress, params->spread);

        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            kbRGB_pset(col_id, row_id, color);
        }
    }
    params->progress += ((params->Speed+speed*20)<<kbRGB_PRE_BIT) / (params->FPS*100);
}

/*************************************************************************************************\
|        MovingPanes [9]                                                                              |
\*************************************************************************************************/
void kbRGB_Int_MovingPanes_Init(struct kbRGB_Int_Params *const params)    // 移动窗格
{
    struct kbRGB_Int_MovingPanes_t *const Panes = &params->Advanced_MovingPanes;
    params->Speed = 30;
    params->Slider2Val = 3;//4;
    params->UserColors[0] = RandomRGBColor();
    params->UserColors[1] = RandomRGBColor();
    Panes->hsv_hue1 = kb_rand() % 360;
    Panes->hsv_hue2 = kb_rand() % 360;//(Panes->hsv_hue1+120+kb_rand()) % 360;
    //Panes->hsv_hue2 = kb_rand() % 360;
}
static uint32_t MovingPanes_GetColor(const int32_t x, const int32_t y, const uint16_t w, const uint16_t h, const uint32_t _time, const uint32_t UserColors[2], const unsigned int Slider2Val, const int reverse)
{
    int zone = x / (w / Slider2Val);
    //int zone_id = zone % 2;
    int zone_id = zone & 0x1;
#if 0
    float pi4 = 3.14 * 0.15;
    float t = reverse ? kbrgb_Params.time : -kbrgb_Params.time;
    float s = 0.5 * (1 + sin((y) / (h * 0.25) + (zone_id ? 1 : -1) * t + pi4));
#else
    int pi4 = 180;
    int32_t t = reverse ? _time : -_time;
    if(1!=zone_id) zone_id=-1;
    //float s = 0.5 * (1 + kbRGB_Sin(( y/(h * 0.25) + (zone_id ? 1 : -1) * t/(float)(0x1<<kbRGB_PRE_BIT))*360/3.14 + pi4)/255.0f);
    //float s = 0.5 * (1 + kbRGB_Sin(( (y<<kbRGB_PRE_BIT)/(h * 0.25) + zone_id * t)*360/3.14/(float)(0x1<<kbRGB_PRE_BIT) + pi4)/255.0f);
    //float s = 0.5 * (1 + kbRGB_Sin(( (y<<(kbRGB_PRE_BIT+2))/h + zone_id * t)*360/3.14/(float)(0x1<<kbRGB_PRE_BIT) + pi4)/255.0f);
    float s = 0.5 * (1 + kbRGB_Sin( ((y<<(kbRGB_PRE_BIT+2))/h + zone_id * t)*360 / (3.14*(0x1<<kbRGB_PRE_BIT)) + pi4)/255.0f);
#endif

    //return Interpolate(UserColors[zone_id ? 1 : 0], UserColors[zone_id ? 0 : 1], s);
    return Interpolate(UserColors[(zone_id+2)&0x1], UserColors[(zone_id+3)&0x1], s);
}
void kbRGB_Int_MovingPanes(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 移动窗格
{
    struct kbRGB_Int_MovingPanes_t *const Panes = &params->Advanced_MovingPanes;
    uint32_t UserColors[2];
    hsv_t hsv;
    //int reverse=1;
    hsv.saturation = 255;
    hsv.value = 255;
    hsv.hue = Panes->hsv_hue1>>2;
    UserColors[0] = hsv2rgb(&hsv);
    hsv.hue = Panes->hsv_hue2>>2;
    UserColors[1] = hsv2rgb(&hsv);
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = MovingPanes_GetColor(col_id, row_id, cols, rows, params->time, UserColors, params->Slider2Val, reverse);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    //time += 0.1 * (float) Speed / (float) FPS;
    params->time += ((params->Speed+speed*10)<<kbRGB_PRE_BIT)/ (params->FPS*10);
    Panes->hsv_hue1++; if(Panes->hsv_hue1>=(360<<2)) Panes->hsv_hue1=0;
    Panes->hsv_hue2++; if(Panes->hsv_hue2>=(360<<2)) Panes->hsv_hue2=0;
}

/*************************************************************************************************\
|        Rain [9]                                                                                 |
\*************************************************************************************************/
void kbRGB_Int_Rain_Init(struct kbRGB_Int_Params *const params)    // 下雨
{
    params->Speed = 30;
	params->FPS = 200;
    params->Slider2Val = 10;
    params->Advanced_Rain.dropsSize = 0;
    kbRGB_clear();
}
static uint32_t Rain_GetColor(unsigned int x, unsigned int y, const struct kbRGB_Int_Rain_t *const Rain)
{
    struct kbRGB_Int_Drop const *drop = NULL;
    for(uint16_t i=0; i<Rain->dropsSize; i++)
    {
        drop = &Rain->drops[i];
        if(drop->col == x)//if(drop.col == x)
        {
            //float distance = drop.progress - y;
            //float distance = (drop->progress - (y<<kbRGB_PRE_BIT))/(float)(0x1<<kbRGB_PRE_BIT);
            int32_t distance = (drop->progress - (y<<kbRGB_PRE_BIT));

            if( (distance >= (0<<kbRGB_PRE_BIT)) && (distance < (3<<kbRGB_PRE_BIT)) )
            {
                //int whole = (int)distance;
                int whole = distance>>kbRGB_PRE_BIT;
                //float frac = /*std::*/modf(distance, &whole);
                //float frac = distance-whole;
                float frac = (distance&kbRGB_PRE_MAX)/(float)(0x1<<kbRGB_PRE_BIT);

                //printf("[%s--%d] drop.col:%2d y:%2d distance:%8f frac:%8f whole:%d \r\n", __func__, __LINE__, drop->col, y, distance, frac, whole);
                //fflush(stdout);
                if (whole == 2) // tail
                {
                    return Enlight(drop->color, 1 - frac);
                }
                else if(whole == 1) // middle
                {
                    return drop->color;
                }
                else // head
                {
                    return Enlight(drop->color, frac);
                }
            }
        }
    }
    return 0x00;
}
static void Rain_TriggerDrop(const unsigned int w, struct kbRGB_Int_Rain_t *const Rain, const unsigned int FPS, const unsigned int Slider2Val)
{
    //unsigned int max_drops = std::min(w, Slider2Val);
    unsigned int max_drops = w;
    int i;
    struct kbRGB_Int_Drop* drop = NULL;
    if(max_drops>Slider2Val) max_drops=Slider2Val;

    if(Rain->dropsSize < max_drops && kb_rand() % (2 + FPS / w) == 0)
    {
        uint32_t color;
        color = RandomRGBColor();

        unsigned int col = kb_rand() % w;   // 通过随机数生成列
        for(i=0; i<Rain->dropsSize; i++)
        {
            drop = &Rain->drops[i];
            if((col==drop->col) && (drop->progress <= ((3)<<kbRGB_PRE_BIT) )) return;
        }
        //float speed_mult = 1 + (float)kb_rand() / ((float)RAND_MAX);
        int32_t speed_mult = kbRGB_PRE_MAX + (kb_rand()&kbRGB_PRE_MAX);
        /*struct kbRGB_Int_Drop* const */drop = &Rain->drops[Rain->dropsSize];
        drop->progress = 0;
        drop->color = color;
        drop->col = col;
        drop->speed_mult = speed_mult;
        Rain->dropsSize++;

    }
}

static void Rain_RunDrops(struct kbRGB_Int_Rain_t *const Rain, const unsigned int FPS, const unsigned int Speed)
{
    //for(Drop& drop: drops[controller_zone_index])
    for(uint16_t i=0; i<Rain->dropsSize; i++)
    {
        //Rain->drops[i].progress += 0.1 * Rain->drops[i].speed_mult * (Speed<<kbRGB_PRE_BIT) / (float) FPS;
        Rain->drops[i].progress += Rain->drops[i].speed_mult * (Speed<<0) / (FPS*10);
        // 浮点运算转整数运算
    }
}

static void Rain_CleanDrops(const signed int h, struct kbRGB_Int_Rain_t *const Rain)
{
    struct kbRGB_Int_Drop* iter=NULL;
    struct kbRGB_Int_Drop* drop1=NULL;
    struct kbRGB_Int_Drop* drop2=NULL;
    for( uint16_t i=0; i<Rain->dropsSize; i++)
    {
        iter=&Rain->drops[i];
        if((iter->progress) > ((h + 3)<<kbRGB_PRE_BIT) )  // 一个雨滴由三个点构成
        {
            if(Rain->dropsSize<=0) break;
            for( uint16_t kk=i; kk<(Rain->dropsSize-1); kk++)
            {
                drop1=&Rain->drops[kk];
                drop2=&Rain->drops[kk+1];
                drop1->progress   = drop2->progress;
                drop1->color      = drop2->color;
                drop1->col        = drop2->col;
                drop1->speed_mult = drop2->speed_mult;
            }
            Rain->dropsSize--;
            break;
        }
    }
}
void kbRGB_Int_Rain(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 下雨
{
    unsigned int w;
    unsigned int h;
    //int reverse=0;
    w = cols;
    h = rows;

    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = Rain_GetColor(col_id, reverse ? rows - row_id - 1: row_id, &params->Advanced_Rain);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    Rain_TriggerDrop(w, &params->Advanced_Rain, params->FPS, params->Slider2Val);
    Rain_RunDrops(&params->Advanced_Rain, params->FPS, params->Speed);
    Rain_CleanDrops(h, &params->Advanced_Rain);
}

/*************************************************************************************************\
|        SmoothBlink [9]                                                                              |
\*************************************************************************************************/
enum PulseRendering {
    Solid = 0,
    Circle = 1
};
void kbRGB_Int_SmoothBlink_Init(struct kbRGB_Int_Params *const params)    // 平滑闪烁
{
    params->Speed = 120;
    params->Slider2Val = 30;
    struct kbRGB_Int_SmoothBlink_t *const Smooth = &params->Advanced_SmoothBlink;
    Smooth->value = 1.0;
    Smooth->random_color_1 = RandomRGBColor();
    Smooth->random_color_2 = RandomRGBColor();
    Smooth->next_color_1 = RandomRGBColor();
    Smooth->next_color_2 = RandomRGBColor();
    //Smooth->interval = 2.0;
    Smooth->strength = 0.5;
    //Smooth->pulses = 2;
    Smooth->pulse_duration = 0.5;
    Smooth->rendering = Circle;
}
static uint32_t SmoothBlink_GetColor(const int32_t x, const int32_t y, const int32_t cx, const int32_t cy, const unsigned int max_distance, struct kbRGB_Int_SmoothBlink_t *const Smooth)
{
    //struct kbRGB_Pixel piont;
    if(Smooth->value >= 1)
    {
        return Smooth->current_color_2;
    }

    //double distance = sqrt(pow(cx - x, 2) + pow(cy - y, 2));
    //piont.pixel = kbRGB_Angle_IntGet((x - cx), (y - cy));
	//int16_t angle = kbRGB_XY2Angle((x - cx), (y - cy));
	uint32_t distance = kbRGB_XY2Radius((x - cx), (y - cy));
    //float distance_percent = distance / max_distance;
    float distance_percent = (float)distance / (float)(max_distance<<KBRGB_XY2RADIUS_PRE);

    float value = Smooth->value + distance_percent;
    //return Interpolate(current_color_1, current_color_2, std::min<double>(1,value + distance_percent));
    if(1>(value)) return Interpolate(Smooth->current_color_1,Smooth->current_color_2, value);
    else return Smooth->current_color_2;//Interpolate(Smooth->current_color_1, Smooth->current_color_2, 1);
}
static void SmoothBlink_HandleSolidRendering(const uint16_t cols, const uint16_t rows, struct kbRGB_Int_SmoothBlink_t *const Smooth)
{
    uint32_t color = Interpolate(Smooth->current_color_1, Smooth->current_color_2, Smooth->value);
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
           kbRGB_pset(col_id, row_id, color);
        }
    }
}

static void SmoothBlink_HandleCircleRendering(const uint16_t cols, const uint16_t rows, struct kbRGB_Int_SmoothBlink_t *const Smooth)
{
    unsigned int width = cols;
    unsigned int height = rows;
    int32_t cx = ((cols<<0) - 1)>>1;// * 0.5;
    int32_t cy = ((rows<<0) - 1)>>1;// * 0.5;

    for(uint16_t h = 0; h < height; h++)
    {
        for(uint16_t w = 0; w <  width; w++)
        {
            uint32_t color = SmoothBlink_GetColor(w<<0, h<<0, cx, cy, (width + height)<<0, Smooth);
            kbRGB_pset(w, h, color);
        }
    }
}
void kbRGB_Int_SmoothBlink(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 平滑闪烁
{
    const float interval = 2.0f;
    const unsigned int pulses = 2;
    struct kbRGB_Int_SmoothBlink_t *const Smooth = &params->Advanced_SmoothBlink;
    if(Smooth->random_fade_timer <= 0.5 * /*Smooth->*/interval)
    {
        Smooth->current_color_1 = Interpolate(Smooth->random_color_1, Smooth->next_color_1, Smooth->random_fade_timer / (0.5 * interval));
        Smooth->current_color_2 = Interpolate(Smooth->random_color_2, Smooth->next_color_2, Smooth->random_fade_timer / (0.5 * interval));
    }
    else
    {
        Smooth->random_color_1 = Smooth->next_color_1;
        Smooth->random_color_2 = Smooth->next_color_2;
    }

    float pulses_total_duration;
    float total_effect_duration;
    pulses_total_duration = /*Smooth->*/pulses * Smooth->pulse_duration;
    total_effect_duration = interval + pulses_total_duration;

    float s = 0.5 + (1 - Smooth->strength) * 0.5;

    if(params->time < interval*kbRGB_PRE_MAX)
    {
        Smooth->value = 1.0;
    }
    else
    {
        float x = (params->time - interval*kbRGB_PRE_MAX)/(float)kbRGB_PRE_MAX;
        //float y = 0.5 * (1 + sin(2 * pulses / pulses_total_duration * x * KBRGB_PI - 0.5 * KBRGB_PI));
        float y = 0.5 * (kbRGB_SinMax + kbRGB_Sin(2 * pulses / pulses_total_duration * x * 180 - 0.5 * 180))/(float)kbRGB_SinMax;
        Smooth->value = y - (y - s) / s;
    }

    switch (Smooth->rendering) {
    case Solid:
        SmoothBlink_HandleSolidRendering(cols, rows, Smooth);
        break;

    case Circle:
        SmoothBlink_HandleCircleRendering(cols, rows, Smooth);
        break;

    default: break;
    }

    params->time += (0x1<<kbRGB_PRE_BIT) / (float) params->FPS;
    Smooth->random_fade_timer += 1.0 / (float) params->FPS;

    if(params->time >= total_effect_duration*kbRGB_PRE_MAX)
    {
        params->time = params->time - total_effect_duration*kbRGB_PRE_MAX;
        Smooth->next_color_1 = RandomRGBColor();
        Smooth->next_color_2 = RandomRGBColor();
        Smooth->random_fade_timer = 0;
    }
}

/*************************************************************************************************\
|        Spiral [9]                                                                              |
\*************************************************************************************************/
static uint32_t kbRGB_Spiral_GetColor(int32_t x, int32_t y, const int16_t w, const int16_t h, const uint32_t _time, const unsigned int Slider2Val, int reverse)
{
//    double angle    = (reverse ? atan2(x - cx, y - cy) :  - atan2(x - cx, y - cy)) * 180 / 3.14159265359;
//    double distance = sqrt(pow(cx - x, 2) + pow(cy - y, 2));
    int16_t dx = w - x*2;
    int16_t dy = h - y*2;
    hsv_t hsv;
    int32_t hue;
    int16_t angle = kbRGB_XY2Angle(dx, dy);
    //printf("%3d, ",  piont.angle>>KBRGB_XY2ANGLE_PRE);
    //printf("(%3d,%3d) %3d, ", dx, dy,  piont.angle>>KBRGB_ANGLE_INT_PRE);
    if(reverse) angle = -angle;
    uint32_t distance = kbRGB_XY2Radius(dx, dy);

    hsv.value = 255;
    // 螺旋
    hue = ((angle)>>KBRGB_XY2ANGLE_PRE) + ((Slider2Val * distance)>>9)-(_time>>(kbRGB_PRE_BIT));
    if(hue<0) hue=-hue;
    hsv.hue = (hue % 360);
    //hsv.hue = abs((int)((angle/8.0f + Slider2Val * distance - time)) % 360);
    //hsv.hue = abs((int)((piontLimit.angle/8.0f + Slider2Val * piontLimit.radius/2.0f - time)) % 360);
    hsv.saturation = 255;

    return (hsv2rgb(&hsv));
}
void kbRGB_Int_Spiral_Init(struct kbRGB_Int_Params *const params)
{
    params->Speed = 80;
    params->Slider2Val = 10;
}
void kbRGB_Int_Spiral(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 螺旋效果
{
//    int32_t cx = ((cols<<0) - 1)>>1;// * 0.5;
//    int32_t cy = ((rows<<0) - 1)>>1;// * 0.5;

    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = kbRGB_Spiral_GetColor(col_id, row_id, cols, rows, params->time, params->Slider2Val, !reverse);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    params->time += ((params->Speed + speed*20)<<kbRGB_PRE_BIT) / params->FPS;
    //if(time>=(360<<kbRGB_PRE_BIT)) time -= (360<<kbRGB_PRE_BIT);
}
static uint32_t kbRGB_Winnower_GetColor(int32_t x, int32_t y, const int16_t w, const int16_t h, const uint32_t _time, const unsigned int Slider2Val, int reverse)
{
    int16_t dx = w - x*2;
    int16_t dy = h - y*2;
    hsv_t hsv;
    int32_t hue;
    int16_t angle = kbRGB_XY2Angle(dx, dy);
    uint32_t distance = kbRGB_XY2Radius(dx, dy);
    if(reverse) angle = -angle;
	hsv.value = 255;
	// 七彩风车
    hue = ((angle*2)>>KBRGB_XY2ANGLE_PRE) + ((Slider2Val * distance/2)>>KBRGB_XY2RADIUS_PRE)-(_time>>(kbRGB_PRE_BIT));
	if(hue<0) hue=-hue;
	hsv.hue = (hue % 360);
	hsv.saturation = 255;
    return (hsv2rgb(&hsv));
}
void kbRGB_Int_Winnower(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 风车效果
{
//    int32_t cx = ((cols<<0) - 1)>>1;// * 0.5;
//    int32_t cy = ((rows<<0) - 1)>>1;// * 0.5;

    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = kbRGB_Winnower_GetColor(col_id, row_id, cols, rows, params->time, params->Slider2Val, !reverse);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    params->time += ((params->Speed + speed*20)<<kbRGB_PRE_BIT) / params->FPS;
    //if(time>=(360<<kbRGB_PRE_BIT)) time -= (360<<kbRGB_PRE_BIT);
}

/*************************************************************************************************\
|        StarryNight [9]                                                                              |
\*************************************************************************************************/
void kbRGB_Int_StarryNight_Init(struct kbRGB_Int_Params *const params)    // 星空
{
    params->Speed = 150;
    params->Slider2Val = 20;
    params->Advanced_StarryNight.CurrentStarsSize = 0;
    const uint16_t cols=KBRGB_ANGLE_SIZE;
    const uint16_t rows=KBRGB_ANGLE_SIZE;
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
           kbRGB_pset(col_id, row_id, 0x00);
        }
    }
}
void kbRGB_Int_StarryNight(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 星空
{
    uint32_t LEDPerCycle = params->Slider2Val;

    //const uint32_t led_size = cols*rows;
	uint16_t cols_id, row_id;
    struct kbRGB_Int_StarryNight_t *const Night = &params->Advanced_StarryNight;

    // Note: this kb_rand() call is the cause, see comment at the top of the file
    // CurrentStars should be a map <ControllerZone*, std::vector<NewStar>>
    // also NewStar should be renamed to "Star" or something more explicit.
    if (kb_rand() % 2)
    {
        if ((Night->CurrentStarsSize < (LEDPerCycle-1)))
        {
            //int StartingLED = 0;//controller_zone->start_idx();
            //int RandomLedID = kb_rand() % (led_size);//controller_zone->leds_count();
			cols_id = kb_rand() % (cols);
			row_id = kb_rand() % (rows);
			int RandomLedID = row_id*cols+cols_id;
            struct kbRGB_Int_NewStar* const LEDStar = &Night->CurrentStars[Night->CurrentStarsSize++];
            //LEDStar->Index = ControllerID;
            LEDStar->LED = RandomLedID;//(StartingLED + RandomLedID);
            // 注: state的计算包含大量浮点运算,这里转换为整形计算,精度为 1/64
            LEDStar->state = 255<<6;
            LEDStar->Color = RandomRGBColor();
        }

    }
    uint16_t _ToBeDeleted=0xFFFF;

    for (uint16_t StarIndex = 0; StarIndex < Night->CurrentStarsSize; StarIndex++)
    {
        hsv_t SetColor;
        rgb2hsv(Night->CurrentStars[StarIndex].Color,&SetColor);

        // 注: state的计算包含大量浮点运算,这里转换为整形计算,精度为 1/64
        int16_t NewValue = (Night->CurrentStars[StarIndex].state - (((params->Speed<<6)*params->FPS) / (1000)));

        if ((NewValue < (1<<6)) || (NewValue > (255<<6)))//if ((NewValue < 1) || (NewValue > 255))
        {
            if(0xFFFF==_ToBeDeleted) _ToBeDeleted=StarIndex;
            SetColor.value = 0;
            kbRGB_pset(Night->CurrentStars[StarIndex].LED%cols, Night->CurrentStars[StarIndex].LED/cols, hsv2rgb(&SetColor));
        }
        else
        {
            // 注: state的计算包含大量浮点运算,这里转换为整形计算,精度为 1/64
            SetColor.value = Night->CurrentStars[StarIndex].state>>6;
            kbRGB_pset(Night->CurrentStars[StarIndex].LED%cols, Night->CurrentStars[StarIndex].LED/cols, hsv2rgb(&SetColor));
            Night->CurrentStars[StarIndex].state -= ((params->Speed<<6) / (params->FPS) );
        }
    }
    if(0xFFFF!=_ToBeDeleted)
    {
        struct kbRGB_Int_NewStar* Star1=NULL;
        struct kbRGB_Int_NewStar const * Star2=NULL;
        for(uint16_t kk=_ToBeDeleted; kk<(Night->CurrentStarsSize-1); kk++)
        {
            Star1=&Night->CurrentStars[kk];
            Star2=&Night->CurrentStars[kk+1];
            Star1->Color = Star2->Color;
            Star1->LED = Star2->LED;
            Star1->state = Star2->state;
        }
        Night->CurrentStarsSize--;
    }
}

/*************************************************************************************************\
|        Sunrise [9]                                                                              |
\*************************************************************************************************/
void kbRGB_Int_Sunrise_Init(struct kbRGB_Int_Params *const params)    // 日出   // Fail
{
    params->Speed = 20;
    params->Slider2Val = 30;
}
void kbRGB_Int_Sunrise(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 日出   // Fail
{
    ;
}
/*************************************************************************************************\
|        SwirlCircles( [9]                                                                              |
\*************************************************************************************************/
static void SwirlCircles_SetRandomColorsEnabled(int RandomColorsEnabled, hsv_t *const hsv1, hsv_t *const hsv2, const uint32_t UserColors[2])
{
    //RandomColorsEnabled = value;

    if(!RandomColorsEnabled)
    {
        //ResetUserColors();
        rgb2hsv(UserColors[0], hsv1);
        rgb2hsv(UserColors[1], hsv2);
    }
    else
    {
        hsv1->hue = 0;
        hsv1->value = 255;
        hsv1->saturation = 255;

        hsv2->hue = 180;
        hsv2->value = 255;
        hsv2->saturation = 255;
    }
}

void kbRGB_Int_SwirlCircles_Init(struct kbRGB_Int_Params *const params)    // 漩涡圈
{
    hsv_t *const hsv1 = &params->Advanced_SwirlCircles.hsv1;
    hsv_t *const hsv2 = &params->Advanced_SwirlCircles.hsv2;
    params->Speed = 50;
    params->Slider2Val = 50;
    params->UserColors[0] = RandomRGBColor();
    params->UserColors[1] = RandomRGBColor();
    SwirlCircles_SetRandomColorsEnabled(1, hsv1, hsv2, params->UserColors);
    params->Advanced_SwirlCircles.radius = 0;
}
static uint32_t SwirlCircles_GetColor(const uint16_t x, const uint16_t y, const uint16_t w, const uint16_t h, const int16_t x1, const int16_t y1, const hsv_t *const hsv1, const hsv_t *const hsv2, const int radius, const unsigned int Slider2Val)
{
    float glow = 0.01 * Slider2Val;

    //double distance1 = sqrt(pow(x1/(float)kbRGB_SinMax - x, 2) + pow(y1/(float)kbRGB_SinMax - y, 2));
    //float distance1_percent = distance1 < radius ? 0 : pow(distance1 / (h+w), glow);
    //struct kbRGB_Pixel point;
    //point.pixel = kbRGB_Angle_IntGet(x1/(float)kbRGB_SinMax - x, y1/(float)kbRGB_SinMax - y);
    //uint16_t _radius = kbRGB_Radius_IntGet(x1 - x*kbRGB_SinMax, y1 - y*kbRGB_SinMax);
    //double distance1 = _radius/(float_t)(0x1<<(KBRGB_RADIUS_INT_PRE+8));
    double distance1 = kb_sqrt(pow(x1 - x*kbRGB_SinMax, 2) + pow(y1 - y*kbRGB_SinMax, 2))/(float)kbRGB_SinMax;
    float distance1_percent = distance1 < radius ? 0 : pow(distance1 / (h+w), glow);
    //float distance1_percent = distance1 / (h+w);

    hsv_t hsv_tmp;

    hsv_tmp.value = hsv1->value * (1 - distance1_percent);
    hsv_tmp.hue = hsv1->hue;
    hsv_tmp.saturation = hsv1->saturation;

    uint32_t color1 = (hsv2rgb(&hsv_tmp));

//    float y2 = h - y1/(float)kbRGB_SinMax;
//    float x2 = w - x1/(float)kbRGB_SinMax;
    int16_t y2 = h*kbRGB_SinMax - y1;
    int16_t x2 = w*kbRGB_SinMax - x1;

    //double distance2 = sqrt(pow(x2 - x, 2) + pow(y2 - y, 2));
    double distance2 = kb_sqrt(pow(x2 - x*kbRGB_SinMax, 2) + pow(y2 - y*kbRGB_SinMax, 2))/(float)kbRGB_SinMax;
    //float distance2_percent = distance2 < radius ? 0 : pow(distance2 / (h+w), glow);
    //float distance2_percent = pow(distance2 / (h+w), glow); if(distance2 < radius) distance2_percent = 0;
    float distance2_percent = pow(distance2 / (h+w), 0.5);

    hsv_tmp.value = hsv2->value * (1 - distance2_percent);
    hsv_tmp.hue = hsv2->hue;
    hsv_tmp.saturation = hsv2->saturation;

    uint32_t color2 = (hsv2rgb(&hsv_tmp));

    return Screen(color1, color2);
}
void kbRGB_Int_SwirlCircles(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 漩涡圈
{
//    float hx = 0.5 * cols;
//    float hy = 0.5 * rows;
    const int16_t hx = cols>>1;
    const int16_t hy = rows>>1;
    hsv_t *const hsv1 = &params->Advanced_SwirlCircles.hsv1;
    hsv_t *const hsv2 = &params->Advanced_SwirlCircles.hsv2;
    //int reverse=0;

//    float y1 = hy + hy * sin(reverse ? -kbRGB_progress : kbRGB_progress);
//    float x1 = hx + hx * cos(reverse ? -kbRGB_progress : kbRGB_progress);
    const int16_t angle = params->progress*180*2/(KBRGB_PI*(0x1<<kbRGB_PRE_BIT));
//    float y1 = hy + hy * kbRGB_Sin_Int(reverse ? -angle : angle)/(float)kbRGB_SinMax;
//    float x1 = hx + hx * kbRGB_Cos_Int(reverse ? -angle : angle)/(float)kbRGB_SinMax;
    int16_t y1 = hy*(kbRGB_SinMax + kbRGB_Sin_Int(reverse ? -angle : angle));///(float)kbRGB_SinMax;
    int16_t x1 = hx*(kbRGB_SinMax + kbRGB_Cos_Int(reverse ? -angle : angle));///(float)kbRGB_SinMax;

    for(uint16_t h = 0; h < rows; h++)
    {
        for(uint16_t w = 0; w <  cols; w++)
        {
            uint32_t color = SwirlCircles_GetColor(w, h, cols, rows, x1, y1, hsv1, hsv2, params->Advanced_SwirlCircles.radius, params->Slider2Val);
            kbRGB_pset(w, h, color);
        }
    }
    //params->progress +=  0.1 * (float) (Speed<<kbRGB_PRE_BIT) / (float) FPS;
    params->progress +=  ((params->Speed+speed*20)<<kbRGB_PRE_BIT) / (params->FPS*10);

    hsv1->hue++;
    hsv2->hue++;
}

/*************************************************************************************************\
|        Wavy [9]                                                                              |
\*************************************************************************************************/
static void Wavy_GenerateRandomColors(struct kbRGB_Int_Wavy_t *const Wavy)
{
    uint32_t color = RandomRGBColor();
    Wavy->RandomColors[0] = color;
    Wavy->RandomColors[1] = Invert(color);
}
void kbRGB_Int_Wavy_Init(struct kbRGB_Int_Params *const params)    // 波形的
{
    params->Speed = 20;
    params->Slider2Val = 30;
    struct kbRGB_Int_Wavy_t *const Wavy = &params->Advanced_Wavy;
    Wavy->Dir = 1 ;
    Wavy->SineProgress      = 10<<kbRGB_PRE_BIT;
    Wavy->WaveProgress      = 60<<kbRGB_PRE_BIT;
    Wavy->WaveFrequency     = 2 <<kbRGB_PRE_BIT;
    Wavy->WaveSpeed         = 30<<kbRGB_PRE_BIT;
    Wavy->OscillationSpeed  = 50;//<<kbRGB_PRE_BIT;
    Wavy_GenerateRandomColors(Wavy);
}
static uint32_t Wavy_GetColor(const int i, const int count, const struct kbRGB_Int_Wavy_t *const Wavy)
{
#if 0
    float pos = (i + (count * Wavy->WaveProgress/(float)(0x1<<kbRGB_PRE_BIT) ) / 100.0f)/count;
    float rad = (360.0f * pos) * KBRGB_PI / 180.0f;
    float wave_height = Wavy->SineProgress/(float)(0x1<<kbRGB_PRE_BIT) * sin(Wavy->WaveFrequency * rad/(float)(0x1<<kbRGB_PRE_BIT));
    float h = 0.5 + wave_height/2;
#else
    int32_t pos = i*100 + ((count * Wavy->WaveProgress)>>kbRGB_PRE_BIT);
    int32_t angle = 2*(360.0f * pos)/(count*100);
    float wave_height = Wavy->SineProgress/(float)(0x1<<kbRGB_PRE_BIT) * kbRGB_Sin_Int((Wavy->WaveFrequency * angle)>>kbRGB_PRE_BIT) / (float)kbRGB_SinMax;
    float h = 0.5 + wave_height/2;
#endif
    return Interpolate(Wavy->RandomColors[0], Wavy->RandomColors[1], h);
}
void kbRGB_Int_Wavy(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 波形的
{
    struct kbRGB_Int_Wavy_t *const Wavy = &params->Advanced_Wavy;
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        uint32_t color = Wavy_GetColor(col_id, cols, Wavy);

        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            kbRGB_pset(col_id, row_id, color);
        }
    }
    if(Wavy->Dir)
    {
        if(Wavy->SineProgress < (1<<kbRGB_PRE_BIT))
        {
            //Wavy->SineProgress += 0.01 * Wavy->OscillationSpeed / FPS;
            Wavy->SineProgress += ((Wavy->OscillationSpeed+speed*10)<<kbRGB_PRE_BIT) / (params->FPS*100);
        }
        else
        {
            Wavy->Dir = 0;//false;
            Wavy->SineProgress -= ((Wavy->OscillationSpeed+speed*10)<<kbRGB_PRE_BIT) / (params->FPS*100);
        }
    }
    else
    {
        if(Wavy->SineProgress > -(1<<kbRGB_PRE_BIT))
        {
            Wavy->SineProgress -= ((Wavy->OscillationSpeed+speed*10)<<kbRGB_PRE_BIT) / (params->FPS*100);

        }
        else
        {
            Wavy->Dir = 1;//true;
            Wavy->SineProgress += ((Wavy->OscillationSpeed+speed*10)<<kbRGB_PRE_BIT) / (params->FPS*100);
        }
    }

    if(/*RandomColorsEnabled && */Wavy->SineProgress >= -0.01f*(0x1<<kbRGB_PRE_BIT) && Wavy->SineProgress <= 0.01f*(0x1<<kbRGB_PRE_BIT))
    {
        Wavy_GenerateRandomColors(Wavy);
    }

    if(Wavy->SineProgress>(0x1<<kbRGB_PRE_BIT))  Wavy->SineProgress= (0x1<<kbRGB_PRE_BIT);
    if(Wavy->SineProgress<-(0x1<<kbRGB_PRE_BIT)) Wavy->SineProgress=-(0x1<<kbRGB_PRE_BIT);

    if(Wavy->WaveProgress < (100<<kbRGB_PRE_BIT))
    {
        //Wavy->WaveProgress += 0.05 * Wavy->WaveSpeed*(0x1<<kbRGB_PRE_BIT) / FPS;
        Wavy->WaveProgress += 5 * Wavy->WaveSpeed / (params->FPS*100);
    } else {
        Wavy->WaveProgress = 0;//.0;
    }
}

/*************************************************************************************************\
|        ZigZag [9]                                                                              |
\*************************************************************************************************/
void kbRGB_Int_ZigZag_Init(struct kbRGB_Int_Params *const params)    // 之字形的
{
    params->Speed = 10;
    params->Slider2Val = 30;
}
#if 1
static uint32_t ZigZag_GetColor(int16_t x, int16_t y, int16_t w, int16_t h, const int32_t _progress)
{
    int32_t total_leds = w * h;
    //int32_t current_led_position = ((int) x % 2 == 0 ? y : h - y - 1 ) + x * h;
    //int32_t current_led_position = ((x&0x1)== 0 ? y : h - y - 1 ) + x * h;
	int32_t current_led_position = ((y&0x1)== 0 ? x : w - x - 1 ) + y * w;
    int32_t current_led_percent = current_led_position*kbRGB_PRE_MAX/total_leds;
    int32_t _current_led_percent = current_led_percent*current_led_percent*current_led_percent;
    int32_t __progress = _progress*_progress*_progress;

    if(current_led_percent < _progress)
    {
        //float distance = pow(current_led_percent / (float)_progress, 3);
        float distance = (_current_led_percent) / (float)(__progress);
        hsv_t hsv;
        //hsv.hue = (int)(distance*360. -100.*time) % 360;
        //hsv.hue = (int)(360+distance*360. -100*_progress/kbRGB_PRE_MAX) % 360;
        hsv.hue = (int)(360+distance*360 -100*_progress/kbRGB_PRE_MAX) % 360;
        hsv.saturation = 255;
        hsv.value = 255;
        hsv.value *= (distance*distance*distance);
        //hsv.value *= 255*_current_led_percent/__progress;
        return (hsv2rgb(&hsv));
    }
    else
    {
        return 0x00;//ColorUtils::OFF();
    }
}
void kbRGB_Int_ZigZag(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 之字形的
{
    //int reverse = 0;
    int32_t _progress = 2*(params->time%(kbRGB_PRE_MAX*params->FPS*100))/(float)(params->FPS*100);
    int16_t x0, y0;
    uint32_t color;
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            x0 = reverse ? cols - col_id - 1: col_id;
            y0 = reverse ? rows - row_id - 1: row_id;
            //uint32_t color = ZigZag_GetColor(reverse ? cols - col_id - 1: col_id, reverse ? rows - row_id - 1: row_id, cols, rows, _progress);
            //color = ZigZag_GetColor(x0, y0, cols, rows, _progress);
            color = ZigZag_GetColor(x0, y0, cols, rows, _progress);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    params->time += ((params->Speed+speed*3)<<kbRGB_PRE_BIT);// / (FPS*100);
    //kbRGB_progress = 2*(kbRGB_time-(long)kbRGB_time);
    //kbRGB_progress = 2*(time%(kbRGB_PRE_MAX*FPS*100))/(float)(kbRGB_PRE_MAX*FPS*100);
}
#else
static uint32_t ZigZag_GetColor(int16_t x, int16_t y, uint16_t w, uint16_t h, const double progress)
{
    int32_t total_leds = w * h;
    //uint16_t current_led_position = ((int) x % 2 == 0 ? y : h - y - 1 ) + x * h;
    int32_t current_led_position = ((y&0x1)== 0 ? x : w - x - 1 ) + y * w;
    float current_led_percent = current_led_position/(float)total_leds;
    const float leds = 0.03f;

    if(current_led_percent < progress)
    {
        float distance = pow(current_led_percent / progress, 3);
        hsv_t hsv;
        //hsv.hue = (int)(distance*360. -100.*time) % 360;
        hsv.hue = (int)(distance*360. -100.*progress) % 360;
        hsv.saturation = 255;
        hsv.value = 255;
        hsv.value *= distance;
        return (hsv2rgb(&hsv));
    }
//    else if(current_led_percent < (progress+leds))
//    {
//        float distance = 1-(current_led_percent - progress)/leds;
//        hsv_t hsv;
//        //hsv.hue = (int)(distance*360. -100.*time) % 360;
//        hsv.hue = (int)(distance*360. -50.*progress) % 360;
//        hsv.saturation = 255;
//        hsv.value = 255;
//        hsv.value *= distance;
//        return (hsv2rgb(&hsv));
//    }
    else
    {
        return 0x00;
    }

}
void kbRGB_Int_ZigZag(const uint16_t cols, const uint16_t rows, const uint8_t , const int reverse, struct kbRGB_Int_Params *const params)    // 之字形的
{
	int16_t x0, y0;
    double Progress = 2*(params->Progress-(long)params->Progress);
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            x0 = reverse ? cols - col_id - 1: col_id;
            y0 = reverse ? rows - row_id - 1: row_id;
            color = ZigZag_GetColor(x0, y0, cols, rows, Progress);
            kbRGB_pset(col_id, row_id, color);
        }
    }

    params->Progress += 0.01 * (float) (params->Speed+speed*3) / (float) params->FPS;
}
#endif

